/***********************************************************
     Starter code for Assignment 3

     This code was originally written by Jack Wang for
		    CSC418, SPRING 2005

		classes defining primitives in the scene

***********************************************************/

#ifndef __Ray_Tracer__SceneObject__
#define __Ray_Tracer__SceneObject__

#include "../Utils/util.h"

class ITextureMapper;

// All primitives should provide a intersection function.  
// To create more primitives, inherit from SceneObject.
// Namely, you can create, Sphere, Cylinder, etc... classes
// here.
class SceneObject
{
public:
	// Returns true if an intersection occured, false otherwise.
	virtual bool intersect( Ray3D&, const Matrix4x4&, const Matrix4x4& ) const = 0;
    
    // Returns true if world point is contained within the object
    virtual bool contains(const Point3D& worldPoint, const Matrix4x4& worldToModel) const = 0;
    
    // Gets the shape id
    int getShapeId() const;
    
    void addTransform(const Matrix4x4& transformation);
    const Matrix4x4& getTransform() const;
    
    void addInvTransform(const Matrix4x4& invTransform);
    const Matrix4x4& getInvTransform() const;
    
    void setMaterial(const Material* material);
    const Material* getMaterial() const;
    
    // Apply rotation about axis 'x', 'y', 'z' angle degrees to node.
	void rotate(char axis, double angle);
    
	// Apply translation in the direction of trans to node.
	void translate(Vector3D trans);
    
	// Apply scaling about a fixed point origin.
	void scale(Point3D origin, double factor[3]);
    
    // Returns the texture mapper for the shape
    virtual const ITextureMapper& getTextureMapper() const;
    
protected:
    
    // Protected constructor
    SceneObject(const Material* material);
    
    Ray3D getRayInObjectSpace(const Ray3D& rayInWorldSpace,
                              const Matrix4x4& worldToModel) const;
    
private:
    int _shapeId;
    Matrix4x4 _transformation;
    Matrix4x4 _invTransformation;
    const Material* _material;
};

// Example primitive you can create, this is a unit square on 
// the xy-plane.
class UnitSquare : public SceneObject {
public:
    UnitSquare(Material* material);
    
	bool intersect( Ray3D& ray, const Matrix4x4& worldToModel,
			const Matrix4x4& modelToWorld ) const;
    
    // Returns true if world point is contained within the object
    virtual bool contains(const Point3D& worldPoint, const Matrix4x4& worldToModel) const;
};

class UnitSphere : public SceneObject {
public:
    UnitSphere(Material* material);
    
	bool intersect( Ray3D& ray, const Matrix4x4& worldToModel,
			const Matrix4x4& modelToWorld ) const;
    
    // Returns true if world point is contained within the object
    virtual bool contains(const Point3D& worldPoint, const Matrix4x4& worldToModel) const;
};

#endif